/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.veditor.model;

import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML;
import offset.nodes.client.editor.model.messages.TemplateInformation;

public class VirtualElement implements Element {

    ArrayList<VirtualElement> children = new ArrayList<VirtualElement>();
    SimpleAttributeSet attributes = new SimpleAttributeSet();
    VirtualElement parent = null;
    String name = null;
    boolean dataElement = false;
    boolean isLeaf = true;
    String content = "";
    boolean multiple = false;
    TemplateInformation typeInformation;
    VirtualBlock virtualBlock;
    public static VirtualElement BINARY = new VirtualElement("binary",  "div");

    private VirtualElement(String internalName, String externalName) {
        this.name = internalName;
        this.virtualBlock = null;
        attributes.addAttribute(StyleConstants.NameAttribute, externalName);
    }

    public VirtualElement(String name, VirtualBlock virtualBlock) {
        this.virtualBlock = virtualBlock;
        this.name = name;
        attributes.addAttribute(StyleConstants.NameAttribute, name);
    }

    public VirtualElement(String name, boolean dataElement, VirtualBlock virtualBlock) {
        this(name, virtualBlock);
        this.virtualBlock = virtualBlock;
        this.dataElement = dataElement;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        VirtualElement clone = new VirtualElement(name, virtualBlock);
        clone.dataElement = dataElement;
        clone.isLeaf = isLeaf;
        if (attributes != null)
            clone.attributes = new SimpleAttributeSet(attributes);
        clone.content = content;
        clone.multiple = multiple;
        if (typeInformation != null)
            clone.typeInformation = (TemplateInformation) typeInformation.clone();
        return clone;
    }

    public TemplateInformation getTypeInformation() {
        return typeInformation;
    }

    public void setTypeInformation(TemplateInformation typeInformation) {
        this.typeInformation = typeInformation;
    }

    VirtualElement pImpliedToVirtualElement(HTML.Tag tag, Element e) {
        VirtualElement result = new VirtualElement(tag.toString(), virtualBlock);
        Element leaf = null;
        if (e.getName().equals(HTML.Tag.IMPLIED.toString()))
            leaf = e.getElement(0);
        else if (e.getName().equals(HTML.Tag.CONTENT.toString()))
            leaf = e;
        ((SimpleAttributeSet) result.getAttributes()).addAttributes((AttributeSet) leaf.getAttributes().getAttribute(tag));
        return result;
    }

    public boolean equals(Element e) {
        if (e == null)
            return false;
        if (isBinary() && (virtualBlock.getModel().isBinary(e)))
            return true;
        if (getName().equals(HTML.Tag.A.toString()) && virtualBlock.getModel().isHyperlink(e))
            e = pImpliedToVirtualElement(HTML.Tag.A, e);
        if (isDataElement() && e.getAttributes().isDefined(DataModel.ATTRIBUTE_NAME_DATA)) {
            String elementDataPath = (String) e.getAttributes().getAttribute(DataModel.ATTRIBUTE_NAME_DATA);
            String virtualDataPath = (String) getAttributes().getAttribute(DataModel.ATTRIBUTE_NAME_DATA);
            if (elementDataPath.equals(virtualDataPath))
                return true;
        }
        else if (!isDataElement() && !e.getAttributes().isDefined(DataModel.ATTRIBUTE_NAME_DATA)) {
             if (isLeaf()) {
                String c1 = getContent().trim();
                String c2 = null;
                try {
                    c2 = virtualBlock.getModel().getContent(e).trim();
                } catch (BadLocationException ex) {
                    Logger.getLogger(VirtualElement.class.getName()).log(Level.SEVERE, null, ex);
                }

                if (!c1.equals(c2))
                    return false;
            }
             
            if (e.getName().equals(getName()))
                return true;
        }               


        return false;
    }

    public boolean isBinary() {
        return getName().equals(BINARY.getName());
    }

    public boolean isMultiple() {
        return multiple;
    }

    public void setMultiple(boolean multiple) {
        this.multiple = multiple;
    }

    public boolean isDataElement() {
        return dataElement;
    }

    public void setDataElement(boolean dataElement) {
        this.dataElement = dataElement;
    }

    public void addChild(VirtualElement child) {
        children.add(child);
        child.setParentElement(this);
        if (!VirtualElement.BINARY.getName().equals(child.getName()))
            isLeaf = false;
    }

    public SimpleAttributeSet getAttributes() {
        return attributes;
    }

    public void setAttributes(SimpleAttributeSet attributes) {
        this.attributes = attributes;
    }

    public Document getDocument() {
        // TODO Auto-generated method stub
        return null;
    }

    public Element getElement(int index) {
        return (Element) children.get(index);
    }

    public VirtualElement getVirtualElement(int index) {
        return (VirtualElement) children.get(index);
    }

    public int getElementCount() {
        return children.size();
    }

    public int getElementIndex(int offset) {
        // TODO Auto-generated method stub
        return 0;
    }

    public int getEndOffset() {
        // TODO Auto-generated method stub
        return 0;
    }

    public String getName() {
        return name;
    }

    public Element getParentElement() {
        return parent;
    }

    public VirtualElement getParent() {
        return parent;
    }

    public void setParentElement(VirtualElement parent) {
        this.parent = parent;
    }

    public int getStartOffset() {
        // TODO Auto-generated method stub
        return 0;
    }

    public boolean isLeaf() {
        return isLeaf;
    }

    public void setIsLeaf(boolean isLeaf) {
        this.isLeaf = isLeaf;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String toString() {
        return name;
    }

    public void setVirtualBlock(VirtualBlock virtualBlock) {
        this.virtualBlock = virtualBlock;
    }

    public VirtualBlock getVirtualBlock() {
        return virtualBlock;
    }

    public int getLevel() {
        int level = 0;
        VirtualElement v = this;
        while (v.getParent() != null) {
            v = v.getParent();
            level++;
        }
        return level;
    }
}
